package com.alibaba.csp.sentinel.dashboard.datasource.entity.jpa;

import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.RuleEntity;
import com.alibaba.csp.sentinel.slots.block.Rule;
import com.alibaba.csp.sentinel.slots.block.flow.ClusterFlowConfig;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;

import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
import java.util.Objects;

/**
 * @author cdfive
 * @date 2018-09-14
 */
@Entity
@Table(name = "tb_ai_monitor_rule")
public class TbAiMonitorRule implements Serializable, RuleEntity {

    private static final long serialVersionUID = 7200023615444172715L;

    @Id
    @Column(name = "id")
    private Long id;
    @Column(name = "app")
    private String app;
    @Column(name = "ip")
    private String ip;
    @Column(name = "port")
    private Integer port;
    @Column(name = "limit_app")
    private String limitApp;
    @Column(name = "resource")
    private String resource;
    /**
     * 0为线程数;1为qps
     */
    @Column(name = "grade")
    private Integer grade;
    @Column(name = "count")
    private Double count;
    @Column(name = "max_count")
    private Double maxCount;
    /**
     * 0为直接限流;1为关联限流;2为链路限流
     ***/
    @Column(name = "strategy")
    private Integer strategy;
    @Column(name = "ref_resource")
    private String refResource;
    /**
     * 0. default, 1. warm up, 2. rate limiter
     */
    @Column(name = "control_behavior")
    private Integer controlBehavior;
    @Column(name = "warm_up_period_sec")
    private Integer warmUpPeriodSec;
    /**
     * max queueing time in rate limiter behavior
     */
    @Column(name = "max_queueing_time_ms")
    private Integer maxQueueingTimeMs;

    @Column(name = "cluster_mode")
    private boolean clusterMode;
    /**
     * Flow rule config for cluster mode.
     */
    @Column(name = "cluster_config")
    private String clusterConfig;

    @Column(name = "gmt_create")
    private Date gmtCreate;
    @Column(name = "gmt_modified")
    private Date gmtModified;

    public static long getSerialVersionUID() {
        return serialVersionUID;
    }

    public void setClusterConfig(String clusterConfig) {
        this.clusterConfig = clusterConfig;
    }

    public String getClusterConfig() {
        return clusterConfig;
    }

    @Override
    public Long getId() {
        return id;
    }

    @Override
    public void setId(Long id) {
        this.id = id;
    }

    @Override
    public String getApp() {
        return app;
    }

    public void setApp(String app) {
        this.app = app;
    }

    @Override
    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    @Override
    public Integer getPort() {
        return port;
    }

    public void setPort(Integer port) {
        this.port = port;
    }

    public String getLimitApp() {
        return limitApp;
    }

    public void setLimitApp(String limitApp) {
        this.limitApp = limitApp;
    }

    public String getResource() {
        return resource;
    }

    public void setResource(String resource) {
        this.resource = resource;
    }

    public Integer getGrade() {
        return grade;
    }

    public void setGrade(Integer grade) {
        this.grade = grade;
    }

    public Double getCount() {
        return count;
    }

    public void setCount(Double count) {
        this.count = count;
    }

    public Double getMaxCount() {
        return maxCount;
    }

    public void setMaxCount(Double maxCount) {
        this.maxCount = maxCount;
    }

    public Integer getStrategy() {
        return strategy;
    }

    public void setStrategy(Integer strategy) {
        this.strategy = strategy;
    }

    public String getRefResource() {
        return refResource;
    }

    public void setRefResource(String refResource) {
        this.refResource = refResource;
    }

    public Integer getControlBehavior() {
        return controlBehavior;
    }

    public void setControlBehavior(Integer controlBehavior) {
        this.controlBehavior = controlBehavior;
    }

    public Integer getWarmUpPeriodSec() {
        return warmUpPeriodSec;
    }

    public void setWarmUpPeriodSec(Integer warmUpPeriodSec) {
        this.warmUpPeriodSec = warmUpPeriodSec;
    }

    public Integer getMaxQueueingTimeMs() {
        return maxQueueingTimeMs;
    }

    public void setMaxQueueingTimeMs(Integer maxQueueingTimeMs) {
        this.maxQueueingTimeMs = maxQueueingTimeMs;
    }

    public boolean isClusterMode() {
        return clusterMode;
    }

    public void setClusterMode(boolean clusterMode) {
        this.clusterMode = clusterMode;
    }

    @Override
    public Date getGmtCreate() {
        return gmtCreate;
    }

    @Override
    public Rule toRule() {
        FlowRule flowRule = new FlowRule();
        flowRule.setCount(this.count);
        flowRule.setGrade(this.grade);
        flowRule.setResource(this.resource);
        flowRule.setLimitApp(this.limitApp);
        flowRule.setRefResource(this.refResource);
        flowRule.setStrategy(this.strategy);
        if (this.controlBehavior != null) {
            flowRule.setControlBehavior(controlBehavior);
        }
        if (this.warmUpPeriodSec != null) {
            flowRule.setWarmUpPeriodSec(warmUpPeriodSec);
        }
        if (this.maxQueueingTimeMs != null) {
            flowRule.setMaxQueueingTimeMs(maxQueueingTimeMs);
        }
        flowRule.setClusterMode(clusterMode);
        ClusterFlowConfig clusterConfig = JSONObject.parseObject(this.clusterConfig, ClusterFlowConfig.class);
        flowRule.setClusterConfig(clusterConfig);
        return flowRule;
    }

    public void setGmtCreate(Date gmtCreate) {
        this.gmtCreate = gmtCreate;
    }

    public Date getGmtModified() {
        return gmtModified;
    }

    public void setGmtModified(Date gmtModified) {
        this.gmtModified = gmtModified;
    }

    public ClusterFlowConfig getClusterConfig2() {
        if (StringUtils.isNotEmpty(clusterConfig)) {
            return JSONObject.parseObject(this.clusterConfig, ClusterFlowConfig.class);
        } else {
            return new ClusterFlowConfig();
        }
    }

    public void setClusterConfig2(ClusterFlowConfig clusterConfig) {
        if (Objects.nonNull(clusterConfig)) {
            this.clusterConfig = JSONObject.toJSONString(clusterConfig);
        } else {
            this.clusterConfig = "";
        }
    }

    public static TbAiMonitorRule fromFlowRuleEntity(FlowRuleEntity flowRuleEntity) {
        TbAiMonitorRule monitorRule = new TbAiMonitorRule();
        BeanUtils.copyProperties(flowRuleEntity, monitorRule);
        ClusterFlowConfig clusterConfig = flowRuleEntity.getClusterConfig();
        monitorRule.setClusterConfig2(clusterConfig);
        return monitorRule;
    }
}
